/*
	Copyright (C) 2009 Salil Bhagurkar
	
	This file is part of ViSE
	
	ViSE is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.
	
	ViSE is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.
	
	You should have received a copy of the GNU Lesser General Public License
	along with ViSE.  If not, see <http://www.gnu.org/licenses/>.
*/


#include <shared.h>

/*Execution system for mathvm nodes*/

/*Supports only integers atm*/


int execute_mathvm(struct mathvm *mathvm)
{
	struct node_stream *stream;
	u32 temp[100]; //Temporary space
	u32 tempctr = 0; //Pointer
	u32 i;
	u32 param0, param1;
	u32 param0_val, param1_val;
	stream = (struct node_stream *)mathvm->stream;
	for(i = 0; i < mathvm->count; i++) {
		param0 = (stream[i].flags & PARAM0_MASK) >> 6;
		param1 = (stream[i].flags & PARAM1_MASK) >> 8;
		switch(param0) {
			case INSTR_CONSTANT: param0_val = stream[i].op0; break;
			case INSTR_SYMBOL  : param0_val = GET_INT(stream[i].node0); break;
			case INSTR_ALLOC   : param0_val = temp[stream[i].alloc0]; break;
		}
		switch(param1) {
			case INSTR_CONSTANT: param1_val = stream[i].op1; break;
			case INSTR_SYMBOL  : param1_val = GET_INT(stream[i].node1); break;
			case INSTR_ALLOC   : param1_val = temp[stream[i].alloc1]; break;
		}
		switch(stream[i].flags & 63) {
			case OP_ADD:
				temp[tempctr++] = param0_val + param1_val;
				break;
			case OP_SUB:
				temp[tempctr++] = param0_val - param1_val;
				break;
			case OP_MUL:
				temp[tempctr++] = param0_val * param1_val;
				break;
			case OP_DIV:
				temp[tempctr++] = param0_val / param1_val;
				break;
			default:
				printk("Invalid instruction\n");
				break;
		}
	}
	struct node_fs *fs;
	u32 transfer_count;
	printk("Sating from %s with %u instructions, result = %u\n", mathvm->name, mathvm->count, temp[tempctr-1]);
	for(i=0; i<mathvm->nr_clients; i++) {
		//printk("--client %s\n", node->client[i]->name);
		if(mathvm->client[i]) {
			if(mathvm->client[i]->type & TYPE_FSMASK) { //Read from a kernel mode system
				if(!(mathvm->type & TYPE_VDATA_NO_OUTGOING)) {
					fs = (struct node_fs *)mathvm->client[i];
					#ifdef DEBUG_EXECUTION
						printk("Write to %s(fs)\n", fs->name);
					#endif
					transfer_count = data_type_size[DATA_TYPE_INT] / (fs->op_unit);
					fs->write(fs, &temp[tempctr-1], 0, transfer_count);
				}
			} else {
				//Check if the node referred to is a vdata. Otherwise just service it(it is a builtin then)
				#ifdef DEBUG_EXECUTION
					printk("--client%u = %s\n", i, mathvm->client[i]->name);
				#endif
				if(mathvm->client[i]->data_type == DATA_TYPE_INT && mathvm->client[i]->type & TYPE_VDATA) {
					*((u32 *)(mathvm->client[i])->data) = temp[tempctr-1];
					service(mathvm->client[i], (struct node *)mathvm, REFER_CLIENT);
				} else {
					service(mathvm->client[i], (struct node *)mathvm, REFER_CLIENT);
				}
			}
		} else
			break;
	}
	
	return 0;
}
